<template>
    <el-form v-if="options" :model="form" size="mini"  :rules="rules" ref="form" v-bind="originProp" v-loading="localFormLoading" @submit.native.prevent>
        <slot name="prepend" v-bind:form="form" v-bind:rules="rules"></slot>
        <template v-for="(rowItem,rowIndex) in $_layoutComputedLayout" >
            <el-row type="flex" :key="rowIndex">
                <template  v-for="(colItem,colIndex) in rowItem">
                    <el-col :span="colItem" :key="colIndex">
                        <template v-for="elementItem in [options[$_layoutIndex(rowIndex,colIndex,$_layoutComputedLayout)]]">
                            <StElDynamicFormItem :form-ext-data="formExtData" :element-item="elementItem" :form="form" :inline="originProp.inline" :form-label-width="originProp.labelWidth" :detail-mode="detailMode">
                                <template v-for="item in getElementItems(elementItem)"  #[item.element.sslot]="scope">
                                    <slot :name="item.element.sslot" v-bind="scope"></slot>
                                </template>
                            </StElDynamicFormItem>
                        </template>
                    </el-col>
                </template>
            </el-row>
        </template>

        <slot name="append" v-bind:form="form" v-bind:rules="rules"></slot>
        <el-form-item v-if="options && options.length > 0" style="text-align: center;display: block;">
            <template v-if="computedSubmitProps.useDefault">
                <StElButton :type="computedSubmitProps.type" native-type="submit" @click="submitForm" :loading="submitLoading || computedSubmitProps.loading">{{computedSubmitProps.label || $stStyleTools.aiStyle(computedSubmitProps.method).text}}</StElButton>
                <StElButton @click="resetForm" >重置</StElButton>
                <StElButton v-if="showBack" @click="goBack" >返回</StElButton>
            </template>
            <slot name="buttons"></slot>
        </el-form-item>
    </el-form>
</template>

<script>

    import layoutMixin from "../../../mixins/LayoutMixin"
    export default {
        name: "StElDynamicForm",
        mixins:[layoutMixin],
        props: {
            formLoading:{
                type: Boolean,
                default: false
            },
            showBack:{
                type: Boolean,
                default: false
            },
            // 被包装组件的原始属性
            originProp: {
                type: Object,
                default: function () {
                    return {}
                }
            },
            /**
             * {
             * field:{
             *     name: '',
             *     value: '',
             *     valueDefault: '',
             *     label: '' // 回显值
             * },
             * element:{
             *     type: '',
             *     label: '', // 标签值
             *     labelShow: true,
             *     required: true,
             *     style: '',
             *     class: ''
             *     
             * }
             * }
             */
            options: {
                type: Array,
                default: function () {
                    return []
                }
            },
            // 提交按钮选项
            submitProps:{
                type: Object,
                default: function () {
                    return {}
                }
            },
            // 表单辅助 主要用来动态修改表单值
            helperForm: {
                type: Object,
                default: function () {
                    return {}
                }
            },
            // 表单初始化数据
            datas:{
                type: [String,Object,Array]
            },
            // 如果 datas 是url 提供一个修改数据的机会
            datasFormat: {
                type: Function,
                default: function (data) {
                    return data
                }
            },
            // 详情模式，因为有的时候详情里面form属性带长路径，导致表单出错
            detailMode:{
                type: Boolean,
                default: false
            }

        },
        computed:{
            computedSubmitProps() {
                let defaultSubmitProps = {
                    url: '',
                    method: 'post',
                    label: '',
                    type: 'primary',
                    msg: '', // 成功消息提示
                  // 是否使用默认的表单下方按钮提交
                    useDefault: true,
                    loading: false,
                  // 表单提交前通知，不需要处理返回值
                    onSubmit: (form)=>{},
                  // 表单提交前，供修改的勾子，如果返回 false ，可以阻止表单的提交
                    dataFormat: (data,formExtData)=>{return data}
                }
                return this.$stObjectTools.extendDeep(defaultSubmitProps,this.submitProps)
            }
        },
        data() {
            return {
                submitLoading: false,
                localFormLoading: this.formLoading,
                form: {},
                rules: {},
                formExtData: {},
                initalDatas: null
            }
        },
        created() {
            this.initForm(this.options)
            this.setFormPropValue(this.helperForm)
            // 默认添加版本字段
            this.$set(this.form,'version',null)
            this.$set(this.formExtData,'version',null)
            this.$set(this.form,'id',null)
            this.$set(this.formExtData,'id',null)
        },
        mounted() {

            this.initData(this.datas)
        },
        methods: {
            goBack(){
                this.$router.go(-1)
            },
            initForm(options){

                if(!options) {
                    return
                }
                options.forEach(elementItem=>{
                    this.initFormItem(elementItem)
                })
            },
            initFormItem(elementItem){
                if(this.$stObjectTools.isObject(elementItem)){
                    let value = elementItem.field.value || elementItem.field.valueDefault || ''
                    if(elementItem.field.value === false || elementItem.field.valueDefault === false){
                        value = false
                    }
                    this.$set(this.form,elementItem.field.name,value)
                    this.$set(this.formExtData,elementItem.field.name,null)
                }else{
                  // 不是对象，就是数据，这里处理数组
                    elementItem.forEach(elementItem=>{
                        this.initFormItem(elementItem)
                    })
                }
            },

            submitForm() {
                this.$refs['form'].validate((valid) => {
                    if (valid) {
                        let data = {}
                        for(let key in this.form){
                            data[key] = this.form[key]
                            if(this.form[key] === ''){
                                data[key] = null
                            }
                        }
                        data = this.computedSubmitProps.dataFormat(data,this.formExtData)
                        // 阻止表单提交
                        if(data === false){
                          console.error('dataFormat 返回false 阻止了表单提交')
                          return
                        }
                        this.computedSubmitProps.onSubmit(this.form,data,this.formExtData)
                        if(!this.computedSubmitProps.url){
                            console.error('url为空直接返回')
                            return
                        }

                        this.submitLoading = true

                        let options = {
                            method: this.computedSubmitProps.method,
                            url: this.computedSubmitProps.url,
                        }
                        if ('get' == options.method) {
                            options.params = data
                        }else {
                            options.data = data
                        }
                        this.axios(options)
                            .then(res=>{
                                this.$message.success(this.computedSubmitProps.msg ||  (this.$stStyleTools.aiStyle(this.computedSubmitProps.method).text +'成功'))
                                this.$emit('requestSuccess',res.data)
                            }).catch(error=>{
                                this.$emit('requestError',error)
                                if(error.response){
                                    if(error.response.data && error.response.data.errorMsg){
                                        this.$message.error(error.response.data.errorMsg)
                                    }
                                }else {
                                    this.$message.error('网络错误或服务不可用')
                                }
                        }).finally(()=>{
                            this.submitLoading = false
                        });
                    } else {
                        return false;
                    }
                });
            },
            resetForm() {
                this.$refs['form'].resetFields();
                if(this.initalDatas){
                    this.initData(this.initalDatas)
                }
            },
            getElementItems(elementItem){
                if (this.$stObjectTools.isObject(elementItem)) {
                    return [elementItem]
                } else {
                    // 认为是数组
                    return elementItem
                }
            },
            getFormRef() {
                return this.$refs['form']
            },
            getFormData() {
                return this.form
            },
            setFormPropValue(helperForm) {
                if(!helperForm){
                    return
                }
                for (let key in helperForm) {
                    if (helperForm[key] !== this.form[key]) {
                        this.$set(this.form,key,helperForm[key])
                        this.$set(this.formExtData,key,null)
                    }
                }

            },
            // 根据url加载数据
            initDataByUrl(url,params) {

                this.localFormLoading = true
                this.axios.get(url,{params: params}).then(res => {
                    this.initData(this.datasFormat(res.data))
                    this.$emit('datasSuccess',res.data)
                }).catch(error => {
                    if (error.response) {
                        if(error.response.data && error.response.data.errorMsg){
                            if (error.response.status == 401) {
                                return
                            }
                            if (error.response.status != 404) {
                                this.$message.error(error.response.data.errorMsg)
                            }
                        }

                    } else {
                        this.$message.error('网络错误或服务不可用')
                    }
                }).finally(()=>{
                    this.localFormLoading = false
                })
            },
            // 加载
            initData(data) {
                if (!data) {
                    return
                }

                if (this.$stObjectTools.isObject(data)) {
                    this.initalDatas = data
                    for(let key in this.form){
                        let value = this.$stObjectTools.getValue(data,key)
                        if (value !== undefined) {
                            this.form[key] = value
                        }
                    }

                } else if (this.$stStringTools.isString(data)) {
                    this.initDataByUrl(data)
                } else if (this.$stFunctionTools.isFunction(data)) {
                    this.initData(data())
                } else if (this.$stArrayTools.isArray(data)) {
                    let url = data[0]
                    let params = {}
                    if (data.length > 1) {
                        params = data[1]
                    }
                    this.initDataByUrl(url,params)
                }
            },
        },
        watch: {
            formLoading(val){
                this.localFormLoading = val
            },
            options(val){
                this.initForm(val)
                if (this.initalDatas) {
                    this.initData(this.initalDatas)
                }
            },
            form:{
                handler(val) {
                    this.$emit('change',val)
                },
                deep: true
            },
            helperForm:{
                handler(val) {
                    this.setFormPropValue(val)
                },
                deep: true
            },
            datas(val) {
                this.initData(val)
            }
        }
    }
</script>

<style scoped>

</style>